package com.ctshk.rpc.order.airexpress.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.ThirdUrlConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.Currency;
import com.ctshk.common.enums.*;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.HttpUtils;
import com.ctshk.common.utils.OperateNumberGenerateUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.common.vo.OrderRefundDTO;
import com.ctshk.rpc.airexpress.dto.AirportExpressDTO;
import com.ctshk.rpc.airexpress.dto.AirportExpressInfoDTO;
import com.ctshk.rpc.airexpress.dto.AirportExpressPriceRemainderDTO;
import com.ctshk.rpc.airexpress.req.AirportExpressIncreaseStrategyPriceQueryReq;
import com.ctshk.rpc.airexpress.service.IAirportExpressService;
import com.ctshk.rpc.booking.req.system.airexpress.add.SupplierOrderSystemAirExpressAddReq;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.finance.json.FileJson;
import com.ctshk.rpc.finance.req.bill.BillAddCollectionReq;
import com.ctshk.rpc.finance.req.bill.BillOperateRefundReq;
import com.ctshk.rpc.finance.req.onaccount.UseQuotaReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.finance.service.IFinanceOnAccountCurrencyQuotaService;
import com.ctshk.rpc.iotc.dto.OperateBankPreferenceQueryDTO;
import com.ctshk.rpc.iotc.req.OperateBankConformQueryReq;
import com.ctshk.rpc.iotc.req.OperateBankDeductReq;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.iotc.service.IOperatePromotionService;
import com.ctshk.rpc.order.airexpress.dto.*;
import com.ctshk.rpc.order.airexpress.dto.mtr.AirportExpressMTRDTO;
import com.ctshk.rpc.order.airexpress.dto.mtr.AirportExpressTicketMTRDTO;
import com.ctshk.rpc.order.airexpress.entity.*;
import com.ctshk.rpc.order.airexpress.enums.AirExpressTouristType;
import com.ctshk.rpc.order.airexpress.enums.MTRProfile;
import com.ctshk.rpc.order.airexpress.mapper.*;
import com.ctshk.rpc.order.airexpress.req.*;
import com.ctshk.rpc.order.airexpress.service.AirportExpressOrderMTRService;
import com.ctshk.rpc.order.airexpress.service.AirportExpressService;
import com.ctshk.rpc.order.airexpress.service.IAirportExpressOrderService;
import com.ctshk.rpc.system.constants.Constants;
import com.ctshk.rpc.system.dto.MainDataCurrencyListDTO;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.enums.CrmMemberProductPointsRateEnum;
import com.ctshk.rpc.system.req.MainDataCurrencyListReq;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.req.UploadReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberUpdatePointsReq;
import com.ctshk.rpc.system.service.*;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 机场快线订单表 服务实现类
 * </p>
 *
 * @author 叶冠峰
 * @since 2021-02-23
 */
@Slf4j
@DubboService
public class AirportExpressOrderServiceImpl extends ServiceImpl<AirportExpressOrderMapper, AirportExpressOrder> implements IAirportExpressOrderService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private AirportExpressService airportExpressServiceComponent;
    @Autowired
    AirportExpressOrderMapper airportExpressOrderMapper;
    @Autowired
    AirportExpressOrderCollectionMapper airportExpressOrderCollectionMapper;
    @Autowired
    AirportExpressOrderTouristMapper airportExpressOrderTouristMapper;
    @Autowired
    AirportExpressOrderRefundMapper airportExpressOrderRefundMapper;
    @Autowired
    AirportExpressOrderReceiptMapper airportExpressOrderReceiptMapper;
    @DubboReference
    ISysUserService sysUserService;
    @DubboReference
    ISysSupplierService sysSupplierService;
    @DubboReference
    IAirportExpressService airportExpressService;
    @DubboReference
    IMainDataCurrencyService mainDataCurrencyService;
    @DubboReference
    IOperatePromotionService operatePromotionService;
    @DubboReference
    IOperateBankPreferenceService operateBankPreferenceService;
    @DubboReference
    ISysApprovalService sysApprovalService;
    @DubboReference
    IFinanceBillService financeBillService;
    @DubboReference
    IFinanceOnAccountCurrencyQuotaService financeOnAccountCurrencyQuotaService;
    @DubboReference
    ICrmMemberService crmMemberService;
    @DubboReference
    ISysPermissionService sysPermissionService;
    @DubboReference
    ISupplierOrderService supplierOrderService;
    @DubboReference
    IFileOSSService fileOSSService;
    @Autowired
    AirportExpressOrderMTRService airportExpressOrderMTRService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result submit(AirportExpressOrderReq airportExpressOrderReq, Long userId) {
        log.info("【机场快线订单-提交订单】提交订单请求:{}", JSON.toJSONString(airportExpressOrderReq));
        UserDTO userDTO = sysUserService.queryCacheUser(userId);
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        LocalDate nowLocalDate = LocalDate.now();
        int adultNumber = airportExpressOrderReq.getAdultTicketNumber();
        int childrenNumber = airportExpressOrderReq.getChildrenTicketNumber() == null ? 0 : airportExpressOrderReq.getChildrenTicketNumber();
        int touristNumber = adultNumber + childrenNumber;
        // 查询加幅后的价格，售卖类型，余票
        AirportExpressIncreaseStrategyPriceQueryReq airportExpressIncreaseStrategyPriceQueryReq = new AirportExpressIncreaseStrategyPriceQueryReq();
        airportExpressIncreaseStrategyPriceQueryReq.setAirportExpressId(airportExpressOrderReq.getAirportExpressId());
        airportExpressIncreaseStrategyPriceQueryReq.setTouristNumber(touristNumber);
        airportExpressIncreaseStrategyPriceQueryReq.setUserId(userDTO.getId());
        if (airportExpressOrderReq.getIsAgent() == 1) {//是否使用代理
            airportExpressIncreaseStrategyPriceQueryReq.setSaleChannelId(Channel.AGENT.getCode());
            airportExpressIncreaseStrategyPriceQueryReq.setAgentId(airportExpressOrderReq.getAgencyId());
        } else {
            airportExpressIncreaseStrategyPriceQueryReq.setSaleChannelId(Channel.AUTARKY.getCode());
        }
        AirportExpressPriceRemainderDTO airportExpressPriceRemainderDTO = airportExpressService.selectPriceRemainderAndLock(airportExpressIncreaseStrategyPriceQueryReq);

        AirportExpressOrder airportExpressOrder = EntityUtil.copy(airportExpressOrderReq, AirportExpressOrder.class);
        //计算订单金额
        BigDecimal orderAmount;
        BigDecimal childrenPrice = null;
        BigDecimal adultPrice = airportExpressPriceRemainderDTO.getAdultPrice();
        BigDecimal adultPriceTotal = adultPrice.multiply(new BigDecimal(adultNumber));
        if (childrenNumber > 0) {
            childrenPrice = airportExpressPriceRemainderDTO.getChildrenPrice();
            BigDecimal childrenPriceTotal = childrenPrice.multiply(new BigDecimal(childrenNumber));
            orderAmount = adultPriceTotal.add(childrenPriceTotal);
        } else {
            orderAmount = adultPriceTotal;
        }
        /**
         * 根据总价计算应收金额，减去会员积分和优惠券
         */
        BigDecimal receivableAmount = buildReceivableAmount(airportExpressOrder, orderAmount);
        //获取机场快线订单编号
        airportExpressOrder.setOrderNumber(airportExpressServiceComponent.generatorOrderNumber(userDTO, nowLocalDateTime));
        // 计算有效期
        airportExpressOrder.setEffectiveTime(nowLocalDate.plusDays(92)); //固定92天有效期
        // 计算付款到期时间,+30分钟
        airportExpressOrder.setPayExpireDate(nowLocalDateTime.plusMinutes(30)); //固定30分钟
        // 获取id
        Long id = SnowflakeIdWorker.nextId();
        // 获取计划汇率 并设置
        airportExpressOrder.setAdultCostPrice(airportExpressPriceRemainderDTO.getAdultCostPrice());
        airportExpressOrder.setAdultCostCurrencyId(Currency.HKD.getCode());
        airportExpressOrder.setAdultCostCurrency(Currency.HKD.getCurrency());
        airportExpressOrder.setAdultCostExchangeRate(BigDecimal.ONE);
        airportExpressOrder.setChildrenCostPrice(airportExpressPriceRemainderDTO.getChildrenCostPrice());
        airportExpressOrder.setChildrenCostCurrencyId(Currency.HKD.getCode());
        airportExpressOrder.setChildrenCostCurrency(Currency.HKD.getCurrency());
        airportExpressOrder.setChildrenCostExchangeRate(BigDecimal.ONE);
        //
        airportExpressOrder.setId(id);
        airportExpressOrder.setOrderAmount(orderAmount);
        airportExpressOrder.setReceivableAmount(receivableAmount);
        airportExpressOrder.setNumber(touristNumber);
        airportExpressOrder.setAdultPrice(adultPrice);
        airportExpressOrder.setChildrenPrice(childrenPrice);
        airportExpressOrder.setContactName(airportExpressOrder.getSurname() + airportExpressOrder.getName());
        airportExpressOrder.setPaymentStatus(OrderPaymentStatus.UN_PAYMENT.getCode()); //未付款
        airportExpressOrder.setScheduledStatus(null);
        airportExpressOrder.setCancelStatus(null);
        airportExpressOrder.setSalesmanId(userDTO.getId());
        airportExpressOrder.setSalesmanName(userDTO.getFullName());
        airportExpressOrder.setIsDeleted(IsDeletedCode.NO.getCode());
        airportExpressOrder.setCreateId(userDTO.getId());
        airportExpressOrder.setGmtCreate(nowLocalDateTime);
        airportExpressOrder.setModifiedId(userDTO.getId());
        airportExpressOrder.setGmtModified(nowLocalDateTime);
        airportExpressOrderMapper.insert(airportExpressOrder);
        // 启动定时任务
        airportExpressServiceComponent.startScheduleTask(id);
        return Result.success(id);
    }

    /**
     * 根据总价计算应收价格，减去会员积分和优惠券
     *
     * @param airportExpressOrder
     * @param orderAmount
     * @return 应收金额
     */
    private BigDecimal buildReceivableAmount(AirportExpressOrder airportExpressOrder, BigDecimal orderAmount) {
        BigDecimal receivableAmount = new BigDecimal(orderAmount.toString());
        //计算应收价格-是否使用积分
        if (airportExpressOrder.getMemberQueryType() != null && airportExpressOrder.getUsingPoints() != null) {
            if (airportExpressOrder.getUsingPoints() <= 0) {
                //抵扣积分必须大于0;
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60021);
            }
            BigDecimal usingPoints = new BigDecimal(String.valueOf(airportExpressOrder.getUsingPoints()));
            // 校验会员积分是否充足
//            checkMemberPoints(airportExpressOrder, usingPoints);
            //计算应收价格-计算积分
            BigDecimal usingPointsCNY = usingPoints.divide(Constants.POINTS_TO_CNY, 2, BigDecimal.ROUND_HALF_UP);
            //人民币兑港币
            MainDataCurrencyListDTO exchangeRateByName = getExchangeRateByName(Currency.CNY.getSymbol());
            BigDecimal crmExchangeRate = exchangeRateByName.getCrmExchangeRate();
            BigDecimal usingPointsHKD = usingPointsCNY.multiply(crmExchangeRate);
            receivableAmount = receivableAmount.subtract(usingPointsHKD);
            if (receivableAmount.compareTo(BigDecimal.ZERO) == -1) {
                // 总价减去积分价后为负数，不予许提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60007);
            }
        }
        //计算应收价格-计算推广码（优惠券）, 机场快线没有推广码业务
        if (airportExpressOrder.getCouponId() != null) {
            // do something 推广码接口未写完，等待中
            /*OperatePromotionConformReq operatePromotionConformReq = new OperatePromotionConformReq();
            operatePromotionConformReq.setActivityCode(airportExpressOrder.getCouponId().toString());
            operatePromotionConformReq.setTotalPaidIn(airportExpressOrder.getOrderAmount());
            operatePromotionConformReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
            operatePromotionConformReq.setRelationId(airportExpressOrder.getAirportExpressId());
            operatePromotionConformReq.setChannelId(airportExpressOrder.getSource().longValue());
            operatePromotionConformReq.setUserId(airportExpressOrder.getModifiedId());
            Result<OperatePromotionQueryDTO> operatePromotionQueryDTOResult = operatePromotionService.queryConform(operatePromotionConformReq);
            if (operatePromotionQueryDTOResult.getCode() != 0) {
                //该订单不满足使用条件
                SystemError systemError = SystemError.getDefined(operatePromotionQueryDTOResult.getCode());
                throw new BusinessException(systemError);
            }
            OperatePromotionQueryDTO data = operatePromotionQueryDTOResult.getData();
            receivableAmount = receivableAmount.subtract(data.getReductionAmount());
            if (receivableAmount.compareTo(BigDecimal.ZERO) == -1) {
                // 总价减去积分价后为负数，不予许提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60007);
            }*/
        }
        return receivableAmount;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result payment(Long id, List<AirportExpressOrderCollectionReq> airportExpressOrderCollectionReqList, Long userId) throws Exception {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectById(id);
        if (airportExpressOrder == null) {
            //订单不存在
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        if (nowLocalDateTime.isAfter(airportExpressOrder.getPayExpireDate())) {
            // 支付超时
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60001);
        }
        UserDTO userDTO = sysUserService.queryCacheUser(userId);
        airportExpressOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_PAYMENT.getCode());
        airportExpressOrder.setModifiedId(userDTO.getId());
        airportExpressOrder.setGmtModified(nowLocalDateTime);
        // 计算支付总金额和支付记录
        BigDecimal amountCountHKD = BigDecimal.ZERO;//订单金额(港币)=实收金额+积分抵扣+优惠券
        BigDecimal readyMoney = BigDecimal.ZERO;//实收金额(港币)
        List<AirportExpressOrderCollection> airportExpressOrderCollectionList = EntityUtil.copyList(airportExpressOrderCollectionReqList, AirportExpressOrderCollection.class);
        List<UseQuotaReq> useQuotaReqList = new ArrayList<>(); // 大客户,代理商挂账
        for (AirportExpressOrderCollection airportExpressOrderCollection : airportExpressOrderCollectionList) {
            if (airportExpressOrderCollection.getCurrencyId() == null) {
                //币种不能为空
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60029);
            }
            // 获取对应汇率，计算支付金额
            MainDataCurrencyQueryDTO currencyQueryDTO = getExchangeRateByName(airportExpressOrderCollection.getCurrencyId());
            BigDecimal marketExchangeRate = currencyQueryDTO.getMarketExchangeRate();
            BigDecimal amountHKD;
            if (airportExpressOrderCollection.getIsUnionpayDiscount() == 1) {
                // 使用银联优惠
                if (airportExpressOrder.getUsingPoints() != null || airportExpressOrder.getCouponId() != null) {
                    //使用了会员积分或优惠券，无法使用银联优惠
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60025);
                }
                useAmountByBankReference(airportExpressOrder, airportExpressOrderCollection, userDTO);
                amountHKD = airportExpressOrderCollection.getCollectionAmount();
            } else {
                amountHKD = airportExpressOrderCollection.getCollectionAmount().multiply(marketExchangeRate);
                readyMoney = readyMoney.add(amountHKD);
            }
            amountCountHKD = amountCountHKD.add(amountHKD);
            String paymentNumber = airportExpressServiceComponent.generatorPaymentNumber(nowLocalDateTime);
            airportExpressOrderCollection.setId(SnowflakeIdWorker.nextId());
            airportExpressOrderCollection.setOrderId(id);
            airportExpressOrderCollection.setCollectionNumber(paymentNumber);
            airportExpressOrderCollection.setCurrency(currencyQueryDTO.getCurrencyCode());
            airportExpressOrderCollection.setStandardAmount(amountHKD);//本位币金额
            airportExpressOrderCollection.setExchangeRate(marketExchangeRate);
            airportExpressOrderCollection.setStatus(null);
            airportExpressOrderCollection.setSalerId(userDTO.getId());
            airportExpressOrderCollection.setSalerName(userDTO.getFullName());
            airportExpressOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
            airportExpressOrderCollection.setCreateId(userDTO.getId());
            airportExpressOrderCollection.setGmtCreate(nowLocalDateTime);
            airportExpressOrderCollection.setModifiedId(userDTO.getId());
            airportExpressOrderCollection.setGmtModified(nowLocalDateTime);
            /**
             * 1，代理商，大客户，挂账付款
             */
            /*if (Objects.equals(airportExpressOrderCollection.getCollectionWayId(), PayRefundMethod.AC.getCode())) {
                UseQuotaReq useQuotaReq = new UseQuotaReq();
                useQuotaReq.setUserId(userId);
                useQuotaReq.setBillNumber(paymentNumber);
                useQuotaReq.setAccountId(airportExpressOrder.getAgencyId());
                useQuotaReq.setAccountType(1);
                useQuotaReq.setCurrencyId(airportExpressOrderCollection.getCurrencyId());
                useQuotaReq.setCurrencyName(currencyQueryDTO.getCurrencyName());
                useQuotaReq.setExchangeRate(marketExchangeRate.doubleValue());
                useQuotaReq.setAmount(airportExpressOrderCollection.getCollectionAmount());
                useQuotaReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
                useQuotaReq.setCollectionWayId(airportExpressOrderCollection.getCollectionWayId());
                useQuotaReq.setCollectionWayName(airportExpressOrderCollection.getCollectionWay());
                useQuotaReq.setCollectionWayId(airportExpressOrderCollection.getCollectionWayId());
                useQuotaReq.setCollectionWayId(airportExpressOrderCollection.getCollectionWayId());
                useQuotaReq.setUserId(userId);
                useQuotaReqList.add(useQuotaReq);
            }*/
        }
        if (CollectionUtils.isNotEmpty(useQuotaReqList)) {
            financeOnAccountCurrencyQuotaService.useQuota(useQuotaReqList);
        }
        // 校验应收价格
        checkAmount(amountCountHKD, airportExpressOrder.getReceivableAmount());
        /**
         * 港铁下单
         */
        AirportExpressMTRDTO airportExpressMTRDTO = airportExpressOrderMTRService.buildAndCreateMtrOrder(airportExpressOrder);
        if (airportExpressMTRDTO == null || CollectionUtils.isEmpty(airportExpressMTRDTO.getTicket())) {
            // 下单失败
            airportExpressOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_FAIL.getCode());
            airportExpressOrderMapper.updateById(airportExpressOrder);
            return Result.failed(SystemError.AIREXPRESS_ORDER_60017);
        }
        /**
         * 上传二维码图片到阿里云
         */
        List<UploadReq> uploadReqList = buildUploadReq(airportExpressOrder.getId(), airportExpressMTRDTO);
        String[] excludeProperties = {"bytes"};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludeFilter = filters.addFilter();
        excludeFilter.addExcludes(excludeProperties);
        log.info("【机场快线订单】批量上传文件,files:{}", JSON.toJSONString(uploadReqList, excludeFilter));
        try {
            fileOSSService.uploadBatch(uploadReqList);
        } catch (Exception e) {
            log.error("【机场快线订单】批量上传文件失败,error:{}", e.getMessage(), e);
        }
        /**
         * 港铁下单成功后
         * 1.减去使用的会员积分，增加消费的产生会员积分
         * 2.减去使用的优惠券(机场快线无优惠券业务)
         * 3.新增会员积分、优惠券的收款记录
         */
        useAndUpdateCrmMemberPoints(airportExpressOrder, readyMoney, userDTO, airportExpressOrderCollectionList);
        // 机场快线车票信息列表
        List<AirportExpressOrderTourist> airportExpressOrderTouristList = new ArrayList<>();
        airportExpressMTRDTO.getTicket().forEach(ticketMtrDto -> {
            AirportExpressOrderTourist airportExpressOrderTourist = new AirportExpressOrderTourist();
            airportExpressOrderTourist.setId(SnowflakeIdWorker.nextId());
            airportExpressOrderTourist.setOrderId(id);
            airportExpressOrderTourist.setThirdTicketNumber(ticketMtrDto.getTid());
//            airportExpressOrderTourist.setThirdTicketQrCode(ticketMtrDto.getQrcode());
            String qrCodeUrl = Constants.FILE_HOST + ticketMtrDto.getFullName();
            airportExpressOrderTourist.setThirdTicketQrCodeUrl(qrCodeUrl);
            //设置旅客类型
            if (ticketMtrDto.getProfile().equals(MTRProfile.ADULT.getCode())) {
                airportExpressOrderTourist.setTouristType(AirExpressTouristType.ADULT.getCode());
            }
            if (ticketMtrDto.getProfile().equals(MTRProfile.CHILDREN.getCode())) {
                airportExpressOrderTourist.setTouristType(AirExpressTouristType.CHILDREN.getCode());
            }
            airportExpressOrderTourist.setIsDeleted(IsDeletedCode.NO.getCode());
            airportExpressOrderTourist.setCreateId(userDTO.getId());
            airportExpressOrderTourist.setGmtCreate(nowLocalDateTime);
            airportExpressOrderTourist.setModifiedId(userDTO.getId());
            airportExpressOrderTourist.setGmtModified(nowLocalDateTime);
            airportExpressOrderTouristList.add(airportExpressOrderTourist);
        });
        /**
         * 生成财务记录
         */
        log.info("【机场快线订单】生成供应商预订，查询机场快线信息, id:{}", airportExpressOrder.getAirportExpressId());
        AirportExpressInfoDTO airportExpressInfoDTO = airportExpressService.selectInfo(airportExpressOrder.getAirportExpressId());
        log.info("【机场快线订单】生成供应商预订，查询机场快线信息, info:{}", JSON.toJSONString(airportExpressInfoDTO));
        /**
         * 生成财务收款记录
         */
        generatorFinance(userId, airportExpressOrder, airportExpressOrderCollectionList, airportExpressInfoDTO);
        /**
         * 生成供应预订单
         */
        UserDTO chargeUser = sysUserService.queryCacheUser(airportExpressInfoDTO.getChargePersonId());
        SupplierOrderSystemAirExpressAddReq supplierOrderSystemAirExpressAddReq = airportExpressServiceComponent.generatorSupplierBooking(airportExpressOrder, chargeUser,
                airportExpressMTRDTO, airportExpressInfoDTO, nowLocalDateTime);
        supplierOrderService.addSystemAirExpress(supplierOrderSystemAirExpressAddReq, userId);
        /**
         * 生成收据
         */
        insertReceipt(airportExpressOrder, userDTO, nowLocalDateTime);

        // 保存订单,生成查询单号
        String inquiryNumber = airportExpressServiceComponent.generatorInquiryNumber();
        airportExpressOrder.setInquiryNumber(inquiryNumber);
        airportExpressOrder.setThirdOrderNumber(airportExpressMTRDTO.getRefNo());
        airportExpressOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
        airportExpressOrderTouristMapper.insertBatchSomeColumn(airportExpressOrderTouristList);
        airportExpressOrderCollectionMapper.insertBatchSomeColumn(airportExpressOrderCollectionList);
        airportExpressOrderMapper.updateById(airportExpressOrder);
        return Result.success(id);
    }

    private void generatorFinance(Long userId, AirportExpressOrder airportExpressOrder, List<AirportExpressOrderCollection> airportExpressOrderCollectionList, AirportExpressInfoDTO airportExpressInfoDTO) {
        List<BillAddCollectionReq> billAddCollectionReqs = new ArrayList<>();
        for (AirportExpressOrderCollection orderCollection : airportExpressOrderCollectionList) {
            List<FileJson> fileJsons = JSON.parseArray(orderCollection.getCollectionCertificateJson(), FileJson.class);
            UserDTO userDTOTemp = sysUserService.queryCacheUser(airportExpressOrder.getSalesmanId());
            BillAddCollectionReq billAddCollectionReq = new BillAddCollectionReq();
            billAddCollectionReqs.add(billAddCollectionReq);
            billAddCollectionReq.setBillNumber(orderCollection.getCollectionNumber());
            billAddCollectionReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
            billAddCollectionReq.setCollectionWayId(orderCollection.getCollectionWayId());
            billAddCollectionReq.setCollectionWayName(orderCollection.getCollectionWay());
            billAddCollectionReq.setCollectionTypeId(CollectionTypeIdCode.FULL.getCode());
            billAddCollectionReq.setCollectionTypeName(CollectionTypeIdCode.FULL.getMsg());
            billAddCollectionReq.setCollectionAmount(orderCollection.getCollectionAmount());
            billAddCollectionReq.setCurrencyId(orderCollection.getCurrencyId());
            billAddCollectionReq.setCurrencyName(orderCollection.getCurrency());
            billAddCollectionReq.setExchangeRate(orderCollection.getExchangeRate().doubleValue());
            billAddCollectionReq.setCollectionTime(orderCollection.getGmtCreate());
            billAddCollectionReq.setCollectionVoucherJsonList(fileJsons); // 收款凭证
            billAddCollectionReq.setSaleOrderNumber(airportExpressOrder.getOrderNumber());
            billAddCollectionReq.setSaleOrderId(airportExpressOrder.getId());
            billAddCollectionReq.setProductId(Arrays.asList(airportExpressOrder.getAirportExpressId()));
            billAddCollectionReq.setProductName(airportExpressInfoDTO.getTicketTypeNameCn());
            billAddCollectionReq.setProductNumber(airportExpressInfoDTO.getProductCode());
            billAddCollectionReq.setResourceInfo(Arrays.asList(airportExpressInfoDTO.getTicketTypeNameCn()));
            billAddCollectionReq.setSaleUserId(airportExpressOrder.getSalesmanId());
            billAddCollectionReq.setSaleUserName(userDTOTemp.getFullName());
            billAddCollectionReq.setSaleDeptId(userDTOTemp.getDeptId());
            billAddCollectionReq.setUserId(userId);
        }
        log.info("【机场快线订单】生成财务收款记录, req:{}", JSON.toJSONString(billAddCollectionReqs));
        financeBillService.addCollection(billAddCollectionReqs);
    }

    /**
     * 上传二维码图片
     *
     * @param airportExpressMTRDTO
     * @return
     */
    private List<UploadReq> buildUploadReq(Long id, AirportExpressMTRDTO airportExpressMTRDTO) {
        List<UploadReq> uploadReqList = new ArrayList<>();
        Base64.Decoder mimeDecoder = Base64.getMimeDecoder();
        for (int i = 0; i < airportExpressMTRDTO.getTicket().size(); i++) {
            AirportExpressTicketMTRDTO ticket = airportExpressMTRDTO.getTicket().get(i);
            UploadReq uploadReq = new UploadReq();
            byte[] bytes = mimeDecoder.decode(ticket.getQrcode().getBytes(StandardCharsets.UTF_8));
            uploadReq.setId(ticket.getTid());
            uploadReq.setBytes(bytes);
            // AIR_EXPRESS-qr-123456789-i.png
            String fullName = SystemBusinessType.AIR_EXPRESS + "-qr-" + id + "-" + i + ".png";
            uploadReq.setFullName(fullName);
            uploadReqList.add(uploadReq);
            ticket.setFullName(fullName);
        }
        return uploadReqList;
    }

    private int insertReceipt(AirportExpressOrder airportExpressOrder, UserDTO userDTO, LocalDateTime nowLocalDateTime) {
        //生成收据单号
        String receiptNumber = airportExpressServiceComponent.generatorReceiptNumber(userDTO, nowLocalDateTime);
        AirportExpressOrderReceipt airportExpressOrderReceipt = new AirportExpressOrderReceipt();
        airportExpressOrderReceipt.setId(SnowflakeIdWorker.nextId());
        airportExpressOrderReceipt.setOrderId(airportExpressOrder.getId());
        airportExpressOrderReceipt.setReceiptNo(receiptNumber);
        airportExpressOrderReceipt.setTransactionTime(nowLocalDateTime);
        airportExpressOrderReceipt.setBranch(userDTO.getDept());
        airportExpressOrderReceipt.setGuest(airportExpressOrder.getContactName());
        airportExpressOrderReceipt.setPhone(airportExpressOrder.getContactMobileAreaCode() + "-" + airportExpressOrder.getContactMobile());
        airportExpressOrderReceipt.setIsDeleted(IsDeletedCode.NO.getCode());
        airportExpressOrderReceipt.setCreateId(userDTO.getId());
        airportExpressOrderReceipt.setGmtCreate(nowLocalDateTime);
        airportExpressOrderReceipt.setModifiedId(userDTO.getId());
        airportExpressOrderReceipt.setGmtModified(nowLocalDateTime);
        return airportExpressOrderReceiptMapper.insert(airportExpressOrderReceipt);
    }

    /**
     * 获取银联优惠金额
     *
     * @param airportExpressOrder
     * @param collection
     * @param user
     * @return
     */
    private void useAmountByBankReference(AirportExpressOrder airportExpressOrder, AirportExpressOrderCollection
            collection, UserDTO user) {
        OperateBankConformQueryReq operateBankConformQueryReq = new OperateBankConformQueryReq();
        operateBankConformQueryReq.setId(collection.getUnionpayDiscountId());//银联优惠ID
        operateBankConformQueryReq.setCardNumber(collection.getPayer());//卡号
        operateBankConformQueryReq.setTotalPaidIn(airportExpressOrder.getOrderAmount());//订单金额
        operateBankConformQueryReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
        operateBankConformQueryReq.setRelationId(airportExpressOrder.getAirportExpressId());//订单ID
        operateBankConformQueryReq.setChannelId(OrderSource.CPM.getCode().longValue());//订单来源
        operateBankConformQueryReq.setUserId(user.getId());
//        operateBankConformQueryReq.setDiscountObjectId();//会员类型
        Result<OperateBankPreferenceQueryDTO> operateBankPreferenceQueryDTOResult = operateBankPreferenceService.queryConform(operateBankConformQueryReq);
        if (!operateBankPreferenceQueryDTOResult.isSuccess()) {
            // 校验银行优惠不满足条件
            SystemError defined = SystemError.getDefined(operateBankPreferenceQueryDTOResult.getCode());
            throw new BusinessException(defined);
        }
        OperateBankPreferenceQueryDTO bankQueryDto = operateBankPreferenceQueryDTOResult.getData();
        if (bankQueryDto.getDiscountType() == 1) {
            // 使用满额折扣优惠
            // 校验应收价格是否符合满减优惠
            if (airportExpressOrder.getReceivableAmount().compareTo(bankQueryDto.getFullAmount()) == -1) {
                // 校验银行优惠不满足条件
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60018);
            }
            collection.setCollectionAmount(bankQueryDto.getReductionAmount());
        } else {
            // 使用百分比优惠
            BigDecimal currentAmount = airportExpressOrder.getReceivableAmount().multiply(new BigDecimal(String.valueOf(bankQueryDto.getDiscountPercent())));
            currentAmount = currentAmount.compareTo(bankQueryDto.getMaxDiscount()) > 0 ? bankQueryDto.getMaxDiscount() : currentAmount;
            collection.setCollectionAmount(currentAmount);
        }
        /**
         * 扣减银联优惠
         */
        OperateBankDeductReq deductReq = new OperateBankDeductReq();
        deductReq.setId(collection.getUnionpayDiscountId());//银联优惠ID
        deductReq.setCardNumber(collection.getPayer());//卡号
        deductReq.setTotalPaidIn(airportExpressOrder.getOrderAmount());//订单金额
        deductReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
        deductReq.setRelationId(airportExpressOrder.getAirportExpressId());//订单ID
        deductReq.setChannelId(OrderSource.CPM.getCode().longValue());//订单来源
//        deductReq.setUserId(user.getId());
        TokenUser tokenUser = new TokenUser();
        tokenUser.setId(user.getId());
        Result deductResult = operateBankPreferenceService.deduct(deductReq, tokenUser);
        if (!deductResult.isSuccess()) {
            // 校验银行优惠不满足条件
            SystemError defined = SystemError.getDefined(deductResult.getCode());
            throw new BusinessException(defined);
        }
    }

    /**
     * 使用和更新crm会员积分
     *
     * @param airportExpressOrder
     * @param readyMoney                             实收金额(现金，信用卡)
     * @param user
     * @param airportExpressOrderCollectionThirdList
     */
    private void useAndUpdateCrmMemberPoints(AirportExpressOrder airportExpressOrder, BigDecimal
            readyMoney, UserDTO user, List<AirportExpressOrderCollection> airportExpressOrderCollectionThirdList) {
        // 更新CRM会员积分记录
        log.info("【机场快线订单】更新会员信息,使用积分:{}, 查询类型:{},查询号:{},证书类型:{}", airportExpressOrder.getUsingPoints(), airportExpressOrder.getMemberQueryType(), airportExpressOrder.getMemberQueryCode(), airportExpressOrder.getMemberQueryCertificatesType());
        if (airportExpressOrder.getUsingPoints() != null && airportExpressOrder.getUsingPoints() > 0) {
            // 获取人民币兑港币汇率
            MainDataCurrencyListDTO mainDataCurrencyListDTO = getExchangeRateByName(Currency.CNY.getCurrency());
            BigDecimal crmExchangeRateCNY = mainDataCurrencyListDTO.getCrmExchangeRate();
            try {
                // 构建创建用户ID，人民币金额，加分点数
                String crmUserId = String.valueOf(user.getId()).substring(0, 12);
                BigDecimal rmbAmount = readyMoney.divide(crmExchangeRateCNY, 2, BigDecimal.ROUND_HALF_UP);
                BigDecimal addPoints = readyMoney.divide(new BigDecimal(String.valueOf(CrmMemberProductPointsRateEnum.TRAFFIC_TYPE.getRate())), BigDecimal.ROUND_DOWN);
                CrmMemberUpdatePointsReq crmMemberUpdatePointsReq = new CrmMemberUpdatePointsReq();
                crmMemberUpdatePointsReq.setUpdateType(2);
                crmMemberUpdatePointsReq.setNumPoints(new BigDecimal(airportExpressOrder.getUsingPoints()));//do积分点数
                crmMemberUpdatePointsReq.setXCtsProdDesc("單項委託-火车巴士船票(机场快线)");//do板塊產品描述 (建議使用: 集團產品名稱 + “ – “ + 板塊產品名稱, 例如: 港澳参团游 - 主题游)")
                crmMemberUpdatePointsReq.setTxnNum(airportExpressOrder.getOrderNumber() + "-1");//do交易編號 (如為旅行團交易, 目前我們的格式是 旅行團交易編號 + ‘-‘ + 序號, 例如: 01P08192131025A155506-1
                crmMemberUpdatePointsReq.setAmtVal(readyMoney);
                crmMemberUpdatePointsReq.setXCtsRmbAmount(rmbAmount);
                crmMemberUpdatePointsReq.setCreateUserid(crmUserId);
                crmMemberUpdatePointsReq.setXCtsTxnOrgCode("219910000010");
                crmMemberUpdatePointsReq.setTxnChannelCd("16");
                crmMemberUpdatePointsReq.setXCtsTxnChnNum("211099000010");
                crmMemberUpdatePointsReq.setProdName("8821090000");
                crmMemberUpdatePointsReq.setXCtsProdCode("8821090300");
                crmMemberService.updatePoints(crmMemberUpdatePointsReq);
                // 新增-加积分记录
                if (readyMoney.compareTo(BigDecimal.ZERO) == -1) {
                    // 实收金额不能小于0
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60020);
                }
                CrmMemberUpdatePointsReq crmMemberIncreasePointsReq = new CrmMemberUpdatePointsReq();
                crmMemberIncreasePointsReq.setUpdateType(1);
                crmMemberIncreasePointsReq.setNumPoints(addPoints);//do积分点数
                crmMemberIncreasePointsReq.setXCtsProdDesc("單項委託-火车巴士船票(机场快线)");//do板塊產品描述 (建議使用: 集團產品名稱 + “ – “ + 板塊產品名稱, 例如: 港澳参团游 - 主题游)")
                crmMemberIncreasePointsReq.setTxnNum(airportExpressOrder.getOrderNumber() + "-2");//do交易編號 (如為旅行團交易, 目前我們的格式是 旅行團交易編號 + ‘-‘ + 序號, 例如: 01P08192131025A155506-1
                crmMemberIncreasePointsReq.setAmtVal(readyMoney);
                crmMemberIncreasePointsReq.setXCtsRmbAmount(rmbAmount);
                crmMemberIncreasePointsReq.setCreateUserid(crmUserId);
                crmMemberIncreasePointsReq.setXCtsTxnOrgCode("219910000010");
                crmMemberIncreasePointsReq.setTxnChannelCd("16");
                crmMemberIncreasePointsReq.setXCtsTxnChnNum("211099000010");
                crmMemberIncreasePointsReq.setProdName("8821090000");
                crmMemberIncreasePointsReq.setXCtsProdCode("8821090300");
                crmMemberService.updatePoints(crmMemberIncreasePointsReq);
                // 新增CRM会员付款方式
                AirportExpressOrderCollection airportExpressOrderCollection = new AirportExpressOrderCollection();
                airportExpressOrderCollection.setId(SnowflakeIdWorker.nextId());
                airportExpressOrderCollection.setOrderId(airportExpressOrder.getId());
                airportExpressOrderCollection.setCollectionAmount(readyMoney);
                airportExpressOrderCollection.setStandardAmount(rmbAmount);
                airportExpressOrderCollection.setCollectionWayId(PayRefundMethod.CRM.getId()); //支付方式：CRM星賞會積分
                airportExpressOrderCollection.setCollectionWay(PayRefundMethod.CRM.getName());
                airportExpressOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
                airportExpressOrderCollection.setCreateId(user.getId());
                airportExpressOrderCollection.setGmtCreate(airportExpressOrder.getGmtModified());
                airportExpressOrderCollection.setModifiedId(user.getId());
                airportExpressOrderCollection.setGmtModified(airportExpressOrder.getGmtModified());
                airportExpressOrderCollectionThirdList.add(airportExpressOrderCollection);
            } catch (Exception e) {
                if (e instanceof BusinessException) {
                    throw e;
                } else {
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60009);
                }
            }
        }
        // 机场快线无优惠券业务
        /*if (airportExpressOrder.getCouponId() != null) {
        }*/
    }

    /**
     * 校验支付金额是否小于应收金额
     *
     * @param amountCountHKD   支付金额
     * @param receivableAmount 应收价格
     */
    private void checkAmount(BigDecimal amountCountHKD, BigDecimal receivableAmount) {
        if (amountCountHKD.compareTo(receivableAmount) < 0) {
            // 支付价格小于应收价格
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60004);
        }
    }

    /**
     * 根据币种ID获取汇率，获取汇率,
     *
     * @return
     */
    private MainDataCurrencyQueryDTO getExchangeRateByName(Long currencyId) {
        MainDataCurrencyUpdateStatusReq mainDataCurrencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
        mainDataCurrencyUpdateStatusReq.setId(currencyId);
        Result<MainDataCurrencyQueryDTO> queryCurrencyRateResult = mainDataCurrencyService.query(mainDataCurrencyUpdateStatusReq);
        log.info("【查询汇率】exchange rate:{}", JSON.toJSONString(queryCurrencyRateResult));
        if (!queryCurrencyRateResult.isSuccess()) {
            SystemError defined = SystemError.getDefined(queryCurrencyRateResult.getCode());
            throw new BusinessException(defined);
        }
        return queryCurrencyRateResult.getData();
    }

    /**
     * 根据币种名称获取汇率
     *
     * @param currencySy
     * @return
     */
    private MainDataCurrencyListDTO getExchangeRateByName(String currencySy) {
        MainDataCurrencyListReq mainDataCurrencyListReq = new MainDataCurrencyListReq();
        mainDataCurrencyListReq.setName(currencySy);
        PageResponse<MainDataCurrencyListDTO> list = mainDataCurrencyService.list(mainDataCurrencyListReq);
        if (CollectionUtils.isEmpty(list.getRecords())) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60003);
        }
        return list.getRecords().get(0);
    }

    private List<MainDataCurrencyQueryDTO> getExchangeRateListByIds(List<Long> currencyIds) {
        List<MainDataCurrencyQueryDTO> mainDataCurrencyQueryDTOS = mainDataCurrencyService.queryList(currencyIds);
        return mainDataCurrencyQueryDTOS;
    }

    @Override
    public Result mtrTest(int type, String reqJson) {
        String url = "";
/*        if (type == 0) {
            url = airportExpressOrderMTRService.MTR_CREATE_ORDER;
        } else if (type == 1) {
            url = airportExpressOrderMTRService.MTR_QUERY_ORDER;
        } else {
            url = airportExpressOrderMTRService.MTR_CANCEL_ORDER;
        }*/
        try {
            log.info("【港铁订单测试】markJsonReq:{}", reqJson);
            String markResultStr = HttpUtils.sendHttpSslPost(url, reqJson);
            log.info("【港铁订单测试】markResultStr:{}", markResultStr);
            return Result.success(markResultStr);
        } catch (Exception e) {
            log.error("【港铁订单测试】失败！msg=[{}]", e);
        }
        return Result.success();
    }

    @Override
    public Result<AirportExpressOrderQueryDTO> query(Long id) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectById(id);
        if (airportExpressOrder == null) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        AirportExpressOrderQueryDTO airportExpressOrderQueryDTO = EntityUtil.copy(airportExpressOrder, AirportExpressOrderQueryDTO.class);
        UserDTO userDto = sysUserService.queryCacheUser(airportExpressOrderQueryDTO.getSalesmanId());
        if (userDto != null) {
            airportExpressOrderQueryDTO.setSalesmanName(String.format("%s/%s", userDto.getFullName(), userDto.getDept()));
        }

        QueryWrapper<AirportExpressOrderTourist> orderTouristQueryWrapper = new QueryWrapper<>();
        orderTouristQueryWrapper.lambda().eq(AirportExpressOrderTourist::getOrderId, id);
        orderTouristQueryWrapper.lambda().eq(AirportExpressOrderTourist::getIsDeleted, IsDeletedCode.NO.getCode());
        List<AirportExpressOrderTourist> airportExpressOrderTourists = airportExpressOrderTouristMapper.selectList(orderTouristQueryWrapper);
        airportExpressOrderQueryDTO.setAirportExpressOrderTouristQueryDTOList(EntityUtil.copyList(airportExpressOrderTourists, AirportExpressOrderTouristQueryDTO.class));

        QueryWrapper<AirportExpressOrderCollection> orderCollectionQueryWrapper = new QueryWrapper<>();
        orderCollectionQueryWrapper.lambda().eq(AirportExpressOrderCollection::getOrderId, id);
        orderCollectionQueryWrapper.lambda().eq(AirportExpressOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode());
        List<AirportExpressOrderCollection> airportExpressOrderCollections = airportExpressOrderCollectionMapper.selectList(orderCollectionQueryWrapper);
        if (CollectionUtils.isNotEmpty(airportExpressOrderCollections)) {
            airportExpressOrderQueryDTO.setAirportExpressOrderCollectionQueryDTOList(EntityUtil.copyList(airportExpressOrderCollections, AirportExpressOrderCollectionQueryDTO.class));
            for (AirportExpressOrderCollectionQueryDTO airportExpressOrderCollectionQueryDTO : airportExpressOrderQueryDTO.getAirportExpressOrderCollectionQueryDTOList()) {
                UserDTO userDTO = sysUserService.queryCacheUser(airportExpressOrderCollectionQueryDTO.getSalerId());
                if (userDTO != null) {
                    airportExpressOrderCollectionQueryDTO.setSaler(String.format("%s/%s", userDTO.getFullName(), userDTO.getDept()));
                }
            }
        }

        QueryWrapper<AirportExpressOrderRefund> orderRefundQueryWrapper = new QueryWrapper<>();
        orderRefundQueryWrapper.lambda().eq(AirportExpressOrderRefund::getOrderId, id);
        orderRefundQueryWrapper.lambda().eq(AirportExpressOrderRefund::getIsDeleted, IsDeletedCode.NO.getCode());
        List<AirportExpressOrderRefund> airportExpressOrderRefunds = airportExpressOrderRefundMapper.selectList(orderRefundQueryWrapper);
        if (CollectionUtils.isNotEmpty(airportExpressOrderRefunds)) {
            airportExpressOrderQueryDTO.setAirportExpressOrderRefundQueryDTOList(EntityUtil.copyList(airportExpressOrderRefunds, AirportExpressOrderRefundQueryDTO.class));
            for (AirportExpressOrderRefundQueryDTO orderRefundQueryDTO : airportExpressOrderQueryDTO.getAirportExpressOrderRefundQueryDTOList()) {
                UserDTO userDTO = sysUserService.queryCacheUser(orderRefundQueryDTO.getCreateId());
                if (userDTO != null) {
                    orderRefundQueryDTO.setApprovalUser(String.format("%s/%s", userDTO.getFullName(), userDTO.getDept()));
                }
            }
        }
        // 构建订单状态
        buildOrderStatus(airportExpressOrderQueryDTO);
        buildAmount(airportExpressOrderQueryDTO);

        AirportExpressInfoDTO airportExpressInfoDTO = airportExpressService.selectInfo(airportExpressOrder.getAirportExpressId());
        airportExpressOrderQueryDTO.setBookingInformation(airportExpressInfoDTO.getBookingInformation());
        if (airportExpressOrder.getUsingPoints() == null && airportExpressOrder.getCouponId() == null) {
            airportExpressOrderQueryDTO.setEnableUnionPayOffer(1);
        } else {
            airportExpressOrderQueryDTO.setEnableUnionPayOffer(0);
        }
        return Result.success(airportExpressOrderQueryDTO);
    }

    /**
     * 构建，应收金额，实收金额，退款金额
     *
     * @param airportExpressOrderQueryDTO
     */
    private void buildAmount(AirportExpressOrderQueryDTO airportExpressOrderQueryDTO) {
        List<AirportExpressOrderRefundQueryDTO> airportExpressOrderRefundList = airportExpressOrderQueryDTO.getAirportExpressOrderRefundQueryDTOList();
        List<AirportExpressOrderCollectionQueryDTO> airportExpressOrderCollections = airportExpressOrderQueryDTO.getAirportExpressOrderCollectionQueryDTOList();
        BigDecimal realAmount = BigDecimal.ZERO;
        BigDecimal refundAmount = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(airportExpressOrderRefundList)) {
            for (AirportExpressOrderRefundQueryDTO refund : airportExpressOrderRefundList) {
                if (Objects.equals(refund.getStatus(), ApprovalStatus.REFUND_SUCCESS.getCode())) {
                    refundAmount = refundAmount.add(refund.getApprovalAmount().multiply(refund.getExchangeRate()));
                }
            }
        }
        if (CollectionUtils.isNotEmpty(airportExpressOrderCollections)) {
            for (AirportExpressOrderCollectionQueryDTO collection : airportExpressOrderCollections) {
                realAmount = realAmount.add(collection.getStandardAmount());
            }
        }
        //计算应收金额
        BigDecimal receivableAmount = airportExpressOrderQueryDTO.getOrderAmount().subtract(refundAmount);
        //计算实收金额
        realAmount = realAmount.subtract(refundAmount);
        airportExpressOrderQueryDTO.setReceivableAmount(receivableAmount);
        airportExpressOrderQueryDTO.setRealAmount(realAmount);
        airportExpressOrderQueryDTO.setRefundAmount(refundAmount);
    }

    /**
     * 构建订单状态
     *
     * @param airportExpressOrderQueryDTO
     */
    private void buildOrderStatus(AirportExpressOrderQueryDTO airportExpressOrderQueryDTO) {
        if (OrderPaymentStatus.UN_PAYMENT.getCode().equals(airportExpressOrderQueryDTO.getPaymentStatus())) {
            if (airportExpressOrderQueryDTO.getScheduledStatus() == null) {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.UN_PAYMENT.getCode());//待付款
            }
        } else if (Objects.equals(OrderPaymentStatus.ALREADY_PAYMENT.getCode(), airportExpressOrderQueryDTO.getPaymentStatus())) {
            if (Objects.equals(airportExpressOrderQueryDTO.getScheduledStatus(), OrderScheduledStatus.CONFIRM_RESERVE.getCode())) {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.CONFIRM_RESERVE.getCode());//待预订
            } else if (Objects.equals(OrderScheduledStatus.RESERVE_SUCCESS.getCode(), airportExpressOrderQueryDTO.getScheduledStatus())) {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.RESERVE_SUCCESS.getCode());//确认成功
            } else {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());//确认失败
            }
        } else if (OrderPaymentStatus.ALREADY_CANCEL.getCode().equals(airportExpressOrderQueryDTO.getPaymentStatus())) {
            airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.ALREADY_CANCEL.getCode());//已取消
        } else {
            airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());//确认失败
        }
    }

    @Override
    public PageResponse<AirportExpressOrderPageDTO> list(AirportExpressOrderListReq airportExpressOrderListReq) {
        //权限控制
        if (airportExpressOrderListReq.getMenuId() == null || airportExpressOrderListReq.getUserId() == null) {
            throw new BusinessException(SystemError.USER_1001);
        }
        Result<List<Long>> permission = sysPermissionService.queryPermission(airportExpressOrderListReq.getMenuId(), airportExpressOrderListReq.getUserId());
        if (!permission.isSuccess()) {
            throw new BusinessException(SystemError.USER_1001);
        }
        List<Long> userList = permission.getData();
        if (CollectionUtils.isEmpty(userList)) {
            return new PageResponse<>(new ArrayList<>(), true, true, 0, 1, 10);
        }
        //查询列表
        Page<AirportExpressOrder> airportExpressOrderPage = new Page<>(airportExpressOrderListReq.getPageNo(), airportExpressOrderListReq.getPageSize());
        QueryWrapper<AirportExpressOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(airportExpressOrderListReq.getOrderNumber() != null, AirportExpressOrder::getOrderNumber, airportExpressOrderListReq.getOrderNumber());
        queryWrapper.lambda().like(StringUtils.isNotBlank(airportExpressOrderListReq.getTicketTypeName()), AirportExpressOrder::getTicketTypeName, airportExpressOrderListReq.getTicketTypeName());
        queryWrapper.lambda().eq(airportExpressOrderListReq.getPaymentStatus() != null, AirportExpressOrder::getPaymentStatus, airportExpressOrderListReq.getPaymentStatus());
        queryWrapper.lambda().eq(airportExpressOrderListReq.getScheduledStatus() != null, AirportExpressOrder::getScheduledStatus, airportExpressOrderListReq.getScheduledStatus());
        queryWrapper.lambda().ge(airportExpressOrderListReq.getFromGmtCreate() != null, AirportExpressOrder::getGmtCreate, airportExpressOrderListReq.getFromGmtCreate());
        queryWrapper.lambda().le(airportExpressOrderListReq.getToGmtCreate() != null, AirportExpressOrder::getGmtCreate, airportExpressOrderListReq.getToGmtCreate());
        queryWrapper.lambda().like(StringUtils.isNotBlank(airportExpressOrderListReq.getContactName()), AirportExpressOrder::getContactName, airportExpressOrderListReq.getContactName());
        queryWrapper.lambda().eq(airportExpressOrderListReq.getSource() != null, AirportExpressOrder::getSource, airportExpressOrderListReq.getSource());
        queryWrapper.lambda().like(StringUtils.isNotBlank(airportExpressOrderListReq.getSalesmanName()), AirportExpressOrder::getSalesmanName, airportExpressOrderListReq.getSalesmanName());
        queryWrapper.lambda().in(AirportExpressOrder::getSalesmanId, userList);
        queryWrapper.lambda().orderByDesc(AirportExpressOrder::getGmtCreate);
        Page<AirportExpressOrder> iPage = airportExpressOrderMapper.selectPage(airportExpressOrderPage, queryWrapper);
        List<AirportExpressOrder> records = iPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());
        }
        List<AirportExpressOrderPageDTO> airportExpressOrderQueryDTOList = EntityUtil.copyList(records, AirportExpressOrderPageDTO.class);
        return new PageResponse<>(airportExpressOrderQueryDTOList, iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result cancel(Long id, AirportExpressOrderCancelReq airportExpressOrderCancelReq, TokenUser currentUser) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectById(id);
        if (airportExpressOrder == null) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        airportExpressOrder.setRefundReason(airportExpressOrderCancelReq.getRefundReason());
        airportExpressOrder.setRemark(airportExpressOrderCancelReq.getRemark());
        if (airportExpressOrder.getPaymentStatus() == OrderPaymentStatus.UN_PAYMENT.getCode()) {
            //未付款，取消订单
            airportExpressOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
        } else if (airportExpressOrder.getPaymentStatus() == OrderPaymentStatus.ALREADY_PAYMENT.getCode()) {
            // 已付款,取消订单
            if (airportExpressOrder.getCancelStatus() != null) {
                //正在取消订单，请勿重复提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60023);
            }
            List<AirportExpressOrderRefundCancelReq> airportExpressOrderRefundCancelList = airportExpressOrderCancelReq.getAirportExpressOrderRefundCancelList();
            if (CollectionUtils.isEmpty(airportExpressOrderRefundCancelList)) {
                // 退款记录不能为空
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60005);
            }
            airportExpressOrder.setCancelStatus(ApprovalStatus.REVIEWING.getCode());
            List<AirportExpressOrderRefund> airportExpressOrderRefundList = EntityUtil.copyList(airportExpressOrderRefundCancelList, AirportExpressOrderRefund.class);
            for (AirportExpressOrderRefund airportExpressOrderRefund : airportExpressOrderRefundList) {
                // 获取对应汇率，计算支付金额
                MainDataCurrencyQueryDTO currencyQueryDTO = getExchangeRateByName(airportExpressOrderRefund.getCurrencyId());
                BigDecimal marketExchangeRate = currencyQueryDTO.getMarketExchangeRate();
                BigDecimal refundAmountHKD = airportExpressOrderRefund.getRefundAmount().multiply(marketExchangeRate);
                airportExpressOrderRefund.setRefundNumber(OperateNumberGenerateUtil.generateRefundNumber(nowLocalDateTime));
                airportExpressOrderRefund.setOrderId(id);
                airportExpressOrderRefund.setCurrency(currencyQueryDTO.getCurrencyCode());
                airportExpressOrderRefund.setExchangeRate(marketExchangeRate);
                airportExpressOrderRefund.setStandardAmount(refundAmountHKD);//本位币金额
                airportExpressOrderRefund.setStatus(ApprovalStatus.REVIEWING.getCode());
                airportExpressOrderRefund.setRefundReason(airportExpressOrderCancelReq.getRefundReason());
                airportExpressOrderRefund.setRemark(airportExpressOrderCancelReq.getRemark());
                airportExpressOrderRefund.setIsDeleted(IsDeletedCode.NO.getCode());
                airportExpressOrderRefund.setCreateId(currentUser.getId());
                airportExpressOrderRefund.setGmtCreate(nowLocalDateTime);
                airportExpressOrderRefund.setModifiedId(currentUser.getId());
                airportExpressOrderRefund.setGmtModified(nowLocalDateTime);
            }
            /**
             * 审批电子流
             */
            log.info("【机场快线订单】submit cancel order approval, business type:{}, approval type:{}", SystemBusinessType.AIR_EXPRESS, SysApprovalType.CANCEL_AIREXPRESS);
            Result<ApprovalStartDTO> startDTOResult = sysApprovalService.start(SystemBusinessType.AIR_EXPRESS.getCode(), SysApprovalType.CANCEL_AIREXPRESS.getCode(), id, currentUser.getId(), airportExpressOrder.getReceivableAmount(), null);
            if (!startDTOResult.isSuccess()) {
                SystemError defined = SystemError.getDefined(startDTOResult.getCode());
                throw new BusinessException(defined);
            }
            airportExpressOrderRefundMapper.insertBatchSomeColumn(airportExpressOrderRefundList);
        } else {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60006);
        }
        airportExpressOrder.setModifiedId(currentUser.getId());
        airportExpressOrder.setGmtModified(nowLocalDateTime);
        int num = airportExpressOrderMapper.updateById(airportExpressOrder);
        return Result.success(num);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateContact(AirportExpressOrderUpdateReq airportExpressOrderUpdateReq, Long userId) {
        AirportExpressOrder airportExpressOrderTemp = airportExpressOrderMapper.selectById(airportExpressOrderUpdateReq.getId());
        if (airportExpressOrderTemp == null) {
            //订单不存在
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        if (airportExpressOrderTemp.getPaymentStatus() != null && airportExpressOrderTemp.getPaymentStatus() == OrderPaymentStatus.ALREADY_PAYMENT.getCode()) {
            // 订单已付款，不允许修改联系人信息
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60010);
        }
        AirportExpressOrder airportExpressOrder = EntityUtil.copy(airportExpressOrderUpdateReq, AirportExpressOrder.class);
        airportExpressOrder.setContactName(airportExpressOrder.getSurname() + airportExpressOrder.getName());
        airportExpressOrder.setModifiedId(userId);
        airportExpressOrder.setGmtModified(LocalDateTime.now());
        return airportExpressOrderMapper.updateById(airportExpressOrder);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Long> confirmRefund(Long id, Long refundId, Long userId) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectById(id);
        if (airportExpressOrder == null) {
            //订单不存在
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        if (!(ApprovalStatus.REVIEW_YES.getCode().equals(airportExpressOrder.getCancelStatus()))) {
            //审批成功状态的订单，才可以做确认退款操作
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60011);
        }
        QueryWrapper<AirportExpressOrderRefund> airportExpressOrderRefundWrapper = new QueryWrapper<>();
        airportExpressOrderRefundWrapper.lambda().eq(AirportExpressOrderRefund::getOrderId, id);
        List<AirportExpressOrderRefund> airportExpressOrderRefunds = airportExpressOrderRefundMapper.selectList(airportExpressOrderRefundWrapper);
        boolean ifAllRefund = true;
        for (AirportExpressOrderRefund airportExpressOrderRefund : airportExpressOrderRefunds) {
            if (refundId.equals(airportExpressOrderRefund.getId())) {
                // 确认退款
                airportExpressOrderRefund.setStatus(ApprovalStatus.REFUND_SUCCESS.getCode());
                airportExpressOrderRefundMapper.updateById(airportExpressOrderRefund);
                /**
                 * 退款记录-确认退款
                 */
                BillOperateRefundReq billOperateRefundReq = new BillOperateRefundReq();
                billOperateRefundReq.setBillNumber(airportExpressOrderRefund.getRefundNumber());
                billOperateRefundReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
                billOperateRefundReq.setUserId(userId);
                log.info("【机场快线订单】再次确认财务退款记录，req:{}", JSON.toJSONString(billOperateRefundReq));
                financeBillService.operateRefund(billOperateRefundReq);
            }
            /**
             * do something暂无支付方式主数据，5-银行优惠，会员积分，优惠券，
             * 除5以外的支付方式记录的状态，有一个不是退款成功，ifAllRefund为false
             */
            if (!(Objects.equals(airportExpressOrderRefund.getRefundWayId(), PayRefundMethod.IYL.getId())) && !(Objects.equals(airportExpressOrderRefund.getStatus(), ApprovalStatus.REFUND_SUCCESS.getCode()))) {
                ifAllRefund = false;
            }
        }
        if (ifAllRefund) {
            // 全部已退款,更新状态
            airportExpressOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
            airportExpressOrder.setCancelStatus(ApprovalStatus.REFUND_SUCCESS.getCode());
            airportExpressOrderMapper.updateById(airportExpressOrder);
        }
        return Result.success(id);
    }

    @Override
    public Result<AirportExpressOrderPayInfoDTO> paymentInfoById(Long id) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectPayInfoById(id);
        AirportExpressOrderPayInfoDTO airportExpressOrderPayInfoDTO = EntityUtil.copy(airportExpressOrder, AirportExpressOrderPayInfoDTO.class);
        if (airportExpressOrder.getUsingPoints() == null && airportExpressOrder.getCouponId() == null) {
            airportExpressOrderPayInfoDTO.setEnableUnionPayOffer(1);
        } else {
            airportExpressOrderPayInfoDTO.setEnableUnionPayOffer(0);
        }
        return Result.success(airportExpressOrderPayInfoDTO);
    }

    @Override
    public BigDecimal getRefundAmount(Long id) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectById(id);
        if (airportExpressOrder == null) {
            //订单不存在
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        BigDecimal cancellationFee = airportExpressService.getCancellationChargeById(airportExpressOrder.getAirportExpressId(), airportExpressOrder.getReceivableAmount());
        return airportExpressOrder.getReceivableAmount().subtract(cancellationFee);
    }

    @Override
    public List<OrderRefundDTO> getRefundList(String orderNumber) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectOne(Wrappers.<AirportExpressOrder>lambdaQuery()
                .eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .eq(AirportExpressOrder::getOrderNumber, orderNumber));
        if (airportExpressOrder == null) {
            //订单不存在
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        List<OrderRefundDTO> orderRefundDTOList = new ArrayList<>();
        List<AirportExpressOrderCollection> airportExpressOrderCollections = airportExpressOrderCollectionMapper.selectList(Wrappers.<AirportExpressOrderCollection>lambdaQuery()
                .eq(AirportExpressOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode())
                .eq(AirportExpressOrderCollection::getOrderId, airportExpressOrder.getId()));
        List<AirportExpressOrderRefund> airportExpressOrderRefunds = airportExpressOrderRefundMapper.selectList(Wrappers.<AirportExpressOrderRefund>lambdaQuery()
                .eq(AirportExpressOrderRefund::getIsDeleted, IsDeletedCode.NO.getCode())
                .eq(AirportExpressOrderRefund::getOrderId, airportExpressOrder.getId()));
        if (CollectionUtils.isEmpty(airportExpressOrderRefunds)) {
            return orderRefundDTOList;
        }
        BigDecimal alreadyAmount = BigDecimal.ZERO;
        for (AirportExpressOrderCollection airportExpressOrderCollection : airportExpressOrderCollections) {
            alreadyAmount = alreadyAmount.add(airportExpressOrderCollection.getStandardAmount());
        }
        for (AirportExpressOrderRefund orderRefund : airportExpressOrderRefunds) {
            OrderRefundDTO orderRefundDTO = new OrderRefundDTO();
            orderRefundDTO.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
            orderRefundDTO.setRefundId(airportExpressOrder.getId());
            orderRefundDTO.setRefundNumber(airportExpressOrder.getOrderNumber());
            orderRefundDTO.setRefundReason(orderRefund.getRefundReason());
            orderRefundDTO.setRemark(orderRefund.getRemark());
            orderRefundDTO.setRefundType(orderRefund.getRefundWay());
            orderRefundDTO.setTotalReceivables(airportExpressOrder.getReceivableAmount());
            orderRefundDTO.setPaidInAmount(alreadyAmount);
            orderRefundDTO.setRefundAmount(orderRefund.getRefundAmount());
            orderRefundDTO.setApprovalAmount(orderRefund.getApprovalAmount()); //审批退款金额
            orderRefundDTO.setCurrency(orderRefund.getCurrency());
            orderRefundDTOList.add(orderRefundDTO);
        }
        return orderRefundDTOList;
    }

    @Override
    public Result<List<MyAirportExpressOrderDTO>> recentToNow(LocalDateTime recent, LocalDateTime now) {
        List<AirportExpressOrder> orderList = baseMapper.selectList(Wrappers.<AirportExpressOrder>lambdaQuery()
                .eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(recent != null, AirportExpressOrder::getGmtModified, recent)
                .le(AirportExpressOrder::getGmtModified, now));

        List<MyAirportExpressOrderDTO> result = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(orderList)) {
            // 后期优化根据orderId集合查询对应的产品
            Result<List<AirportExpressDTO>> listResult = airportExpressService.selectProductList();
            Map<Long, AirportExpressDTO> map = new HashMap<>();
            List<Long> orderIdList = new ArrayList<>();
            if (listResult.isSuccess()) {
                List<AirportExpressDTO> data = listResult.getData();
                map = data.stream().collect(Collectors.toMap(AirportExpressDTO::getId, Function.identity()));
            }
            for (AirportExpressOrder airportExpressOrder : orderList) {
                MyAirportExpressOrderDTO orderDTO = EntityUtil.copy(airportExpressOrder, MyAirportExpressOrderDTO.class);
                AirportExpressDTO airportExpressDTO = map.get(orderDTO.getId());
                if (airportExpressDTO != null) {
                    orderDTO.setTicketTypeEnName(airportExpressDTO.getTicketTypeNameEn());
                }
                orderIdList.add(orderDTO.getId());
                result.add(orderDTO);
            }

            if (CollectionUtils.isNotEmpty(orderIdList)) {
                List<AirportExpressOrderTourist> airportExpressOrderTourists = airportExpressOrderTouristMapper.selectList(Wrappers.<AirportExpressOrderTourist>lambdaQuery()
                        .in(AirportExpressOrderTourist::getOrderId, orderIdList));

                Map<Long, AirportExpressOrderTourist> collect = airportExpressOrderTourists.stream().collect(
                        Collectors.toMap(AirportExpressOrderTourist::getOrderId, Function.identity(), (key1, key2) -> key1));

                for (MyAirportExpressOrderDTO orderDTO : result) {
                    AirportExpressOrderTourist airportExpressOrderTourist = collect.get(orderDTO.getId());
                    if (airportExpressOrderTourist != null) {
                        orderDTO.setTicketQrCodeUrl(airportExpressOrderTourist.getThirdTicketQrCodeUrl());
                    }
                }
            }

        }
        return Result.success(result);
    }

    @Override
    public List<AirportExpressOrderDTO> queryOrderDTOList(LocalDateTime start, LocalDateTime end) {
        return EntityUtil.copyList(baseMapper.selectList(Wrappers.<AirportExpressOrder>lambdaQuery()
                .eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(AirportExpressOrder::getGmtCreate, start)
                .le(AirportExpressOrder::getGmtCreate, end)),AirportExpressOrderDTO.class);
    }

}
